/*
 * =====================================================================================
 *
 *       Filename:  test_queues.cxx
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  02/17/2011 09:28:08 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Ken Chen (Ken), chen_kenz@emc.com
 *        Company:  EMC
 *
 * =====================================================================================
 */

#include <iostream>
#include <string>
#include <functional>
#include <memory>
#include "cl_thread.hxx"
#include "cl_pc_queue.hxx"
#include "cl_lockfree_queue.hxx"
#include "cl_singleton.hxx"

using namespace std;
using namespace neo;

class Base
{
public:
  Base(int i)
    : m_index(i)
  {
  }

  virtual void print(void) const
  {
    cout << "Base:: " << getIndex() << "\n";
  }

  int getIndex(void) const
  {
    return m_index;
  }

private:
  int m_index;
};


class Derive: public Base
{
public:
  Derive(int i)
    :Base(i)
  {
  }

  virtual void print(void) const
  {
    cout << "Derive:: " << getIndex() << "\n";
  }
};

class Consumer
{
public:
	Consumer()
	{
    m_thr = unique_ptr<CLThread>(new CLThread(bind(&Consumer::consume, this)));
  }
	
  ~Consumer()
	{
		m_thr->join();
	}

  void startConsume( void )
  {
		m_thr->start();
  }

	void consume( void )
	{
    bool result = false;
    for(;;)
    {
      //unique_ptr<int> up; 
      unique_ptr<Base> base;
      result = CLSingleton<CLLockFreeQueue<unique_ptr<Base> > >::instance()->pop(base);
      if(result)
      {
        cout << "Consumed unique_ptr " << base->getIndex() << "\n";
      }

      Base* pBase = NULL;
      result = CLSingleton<CLLockFreeQueue<Base*> >::instance()->pop(pBase);
      if(result)
      {
        cout << "Consumed raw " << pBase->getIndex() << "\n";
      }
    }
  }

private:
	unique_ptr<CLThread> m_thr;
};

class Producer
{
public:
	Producer()
	{
	  m_thr = unique_ptr<CLThread>(new CLThread(bind(&Producer::produce, this)));
  }

  ~Producer()
	{
		m_thr->join();
	}

	void startProduce( void )
	{
		m_thr->start();
	}

	void produce( void )
	{
    int i = 0;
    int j = 0;
    for(;;)
    {
      CLSingleton<CLLockFreeQueue<unique_ptr<Base> > >::instance()->push(unique_ptr<Base>(new Derive(++i)));
      CLSingleton<CLLockFreeQueue<Base*> >::instance()->push(new Derive(++j));
      cout << "Produced " << i << " " << j << "\n";
			sleep(1);
     }
	}

private:
	unique_ptr<CLThread> m_thr;
};


int main( int argc, char *argv[] )
{
  // Init the queue
  CLSingleton<CLLockFreeQueue<unique_ptr<Base> > >::create();
  CLSingleton<CLLockFreeQueue<Base*> >::create();

  // Start up the producer thread
  Producer pt1;
  pt1.startProduce();

  Producer pt2;
  pt2.startProduce();

  sleep(3);
  // Start up the consumer threads
  Consumer ct1;
  ct1.startConsume();

#if 1
  Consumer ct2;
  ct2.startConsume();

  Consumer ct3;
  ct3.startConsume();
#endif 

	return 0;
}

